/*
*/

#include <learning.h>
#include <beam.h>
#include <decode.h>
#include <display.h>
#include <event.h>
#include <form.h>
#include <keypad.h>
#include <timer.h>
#include <usb.h>

#define	DEBUG

#define	FORM_LEN	450
#define	FORM_END	0
#define	SIGNAL_CCR	CCR2
#define	SIGNAL_DMA	DMA1_Channel7
#define	SIGNAL_TIM	TIM2

typedef struct _BEAMX{
    u16	key;
    u16	period;
    u16	pulse;
    u16	repetition;
    u16	timeout;
    u16	head;
    u16	tail;
    u16	wave[200];
}BEAMX;

static U32	Send	(U32*,U32*,U32,U32);
static void	Stop	(void);

static u16	form[256];
//static FORM	borm;

static U32 BeamIn(U32 dmo,U32 *dst,U32 dsn){
    U32	cnt,dmc,dur,seq,t_m,tmc,vlc,vlo;
    U32	*dss,*dsx;
    S32	dlt,prc,pro;
    U16	*bux,*src,*srx;

    if((dmc=DMA_GetCurrDataCounter(SIGNAL_DMA))==dmo)
	return 0;
    dss=dst;
    bux=form+countof(form);
    src=bux-dmo;
    srx=bux-dmc;
    vlo=*src;
    cnt=dur=pro=seq=0;
    tmc=0;
    t_m=Timer();
    for(dsx=dst+dsn-1;dst<dsx;){
	vlc=*src;
	src++;
	if(src>=bux)
	    src=form;
	prc=(vlc-vlo)&0xffff;
	dlt=pro?pro-prc:0;
	if(dlt>2||dlt<-2){
	    *dst++=(cnt<<CNT_SHIFT)+dur;
	    cnt=0;
	    dur=prc;
	}
	else{
	    dur+=prc;
	    cnt++;
	}
	vlo=vlc;
	pro=prc;
	if(src==srx){
	    tmc=clock;
	    seq=Send(dss,dst,seq,0);
	    dmo=dmc;
	    while(dmo==dmc){
		__WFI();
		Display();
		if(TimeOut(t_m,512))
		    goto End;
		dmc=DMA_GetCurrDataCounter(SIGNAL_DMA);
	    }
	    srx=bux-dmc;
	    tmc=clock-tmc;
	}
    }
End:
    *dst++=0;
    seq=Send(dss,dst,seq,1);
    return seq;
}

static U32 DecodeEx(BEAM *beam){
    SLOT o[SLOT_LEN];
    KEY	 k;

    Fact(beam,o);
//    return Decode(beam,&k);
    return 0;
}

static u32 Press(u32 evn,u32 stt){
    u32	key;
    if((key=GetKey(evn))==KEY_PROG){
	IndicatorOn();
	return MOD_NIL;
    }
    BeamOn(key);
    do evn=WaitEvent();
    while(evn!=EVN_KEYRELEASE);
    BeamOff();
    return stt;
}

static U32 Send(U32 *buf,U32 *pos,U32 seq,U32 lst){
    buf+=seq*15;
    while(buf+15<pos){
	SendWave(buf,seq,0);
	buf+=15;
	seq++;
    }
    if(lst){
	SendWave(buf,seq,1);
	seq++;
    }
    return seq;
}

static u32 Start(void){
    TIM_TimeBaseInitTypeDef	b;
    TIM_ICInitTypeDef           i;
    DMA_InitTypeDef             d;

    b.TIM_Period	=0xffff;
    b.TIM_Prescaler	=144;
    b.TIM_ClockDivision	=0;
    b.TIM_CounterMode	=TIM_CounterMode_Up;
    TIM_TimeBaseInit(SIGNAL_TIM,&b);
    i.TIM_Channel	=TIM_Channel_2;
    i.TIM_ICPolarity	=TIM_ICPolarity_Rising;
    i.TIM_ICSelection	=TIM_ICSelection_DirectTI;
    i.TIM_ICPrescaler	=TIM_ICPSC_DIV1;
    i.TIM_ICFilter	=0;
    TIM_ICInit(SIGNAL_TIM,&i); 
    d.DMA_PeripheralBaseAddr=(u32)&SIGNAL_TIM->SIGNAL_CCR;
    d.DMA_MemoryBaseAddr=(u32)form;
    d.DMA_BufferSize	=countof(form);
    d.DMA_DIR		=DMA_DIR_PeripheralSRC;
    d.DMA_PeripheralInc	=DMA_PeripheralInc_Disable;
    d.DMA_MemoryInc	=DMA_MemoryInc_Enable;
    d.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;
    d.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;
    d.DMA_Mode		=DMA_Mode_Circular;
    d.DMA_Priority	=DMA_Priority_High;
    d.DMA_M2M		=DMA_M2M_Disable;
    DMA_Init(SIGNAL_DMA,&d);
    DMA_Cmd(SIGNAL_DMA,ENABLE);
    TIM_DMACmd(SIGNAL_TIM,TIM_DMA_CC2,ENABLE);
    TIM_Cmd(SIGNAL_TIM,ENABLE);
    return DMA_GetCurrDataCounter(SIGNAL_DMA);
}

static void Stop(void){
    DMA_Cmd(SIGNAL_DMA,DISABLE);
    TIM_Cmd(SIGNAL_TIM,DISABLE);
}

//------------------------------------------------------------------------------

u32 Learning(u32 stt){
    u32	evn,dmo,t_m;
    
    FlashOn();
    t_m=Timer();
    dmo=Start();
    while(stt>=MOD_PRESET){
	evn=WaitEvent();
	if((evn&EVN_MASK)==EVN_KEYPRESS){
	    Stop();
	    if(stt=Press(evn,stt)){
		dmo=Start();
		t_m=Timer();
	    }
	}
	/*
	if(TimeOut(t_m,TIM_OUT)){
	    Stop();
	    IndicatorOff();
	    stt=MOD_NIL;
	}
	*/
	if(BeamIn(dmo,beam.form,countof(beam.form))){
	    Stop();
	    if(DecodeEx(&beam))
		stt=MOD_SIGNAL;
	    else{
		Delay(500);
		t_m=Timer();
		dmo=Start();
	    }
	}
    }
    return stt;
}
